/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.hyk.appcfg.wrapper.invoker;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Administrator
 */
public class AppCfgInvoker {

    static class RedirectOutput implements Runnable {

        InputStream is;
        AppCfgOutput newOut;
        AppCfgInput newIn;

        public RedirectOutput(InputStream is, AppCfgOutput newOut, AppCfgInput newIn) {
            this.is = is;
            this.newOut = newOut;
            this.newIn = newIn;
        }
        boolean running = true;

        public void stop() {
            this.running = false;
        }

        public void run() {
            byte[] data = new byte[4096];
            while (running) {
                try {
                    int len = is.read(data);
                    if (len > 0) {
                        String out = new String(data, 0, len);
                        newOut.out(out);
                        if (out.startsWith("Password for")) {
                            newIn.in();
                        }
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

        }
    }

    static class PasswordInput implements AppCfgInput {

        private String passwd;
        OutputStream os;

        public void in() {
            try {
                os.write(passwd.getBytes());
                os.flush();
            } catch (IOException ex) {
                Logger.getLogger(AppCfgInvoker.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        public PasswordInput(String passwd, OutputStream os) {
            this.passwd = passwd + System.getProperty("line.separator");
            this.os = os;
        }
    }

    public static void execute(final List<AppCfgTask> tasks, final AppCfgOutput newOut) throws IOException {
        new Thread(new Runnable() {

            public void run() {
                try {
                    for (AppCfgTask task : tasks) {
                        task.preExecute();
                        ProcessBuilder pb = new ProcessBuilder(task.buildCommand());
                        pb.redirectErrorStream();
                        Process p = pb.start();
                        PasswordInput pin = new PasswordInput(task.passwd, p.getOutputStream());
                        RedirectOutput stdin = new RedirectOutput(p.getInputStream(), newOut, pin);
                        RedirectOutput stderr = new RedirectOutput(p.getErrorStream(), newOut, pin);
                        try {
                            new Thread(stdin).start();
                            new Thread(stderr).start();
                            p.waitFor();
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            stdin.stop();
                            stderr.stop();
                            p.destroy();
                            newOut.out("AppCfgTask finished." + System.getProperty("line.separator"));
                            newOut.out("==================================");
                        }
                    }

                } catch (IOException ex) {
                    Logger.getLogger(AppCfgInvoker.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }).start();
    }

    public static void execute(final AppCfgTask task, final AppCfgOutput newOut) throws IOException {
        List<AppCfgTask> tasks = new LinkedList<AppCfgTask>();
        tasks.add(task);
        execute(tasks, newOut);
    }
}
